/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package idea.sfo.viewer.designer;


import designersfo.Cons.CellInfo;
import designersfo.Cons.CellInfo.CellFormat;
import designersfo.Cons.CellInfo.CustomContentCellData;
import idea.model.dbmanager.SfoDbManager;
import idea.model.dbmanager.SfoEnum;
import idea.model.qnrlibrary.CustomResponses;
import idea.model.qnrlibrary.DcAttributeGroup;
import idea.model.qnrlibrary.PaperAttributeGroup;
import idea.sfo.utils.SfoDocumentManager;
import idea.sfo.viewer.Canvas;
import idea.sfo.viewer.graphics.CellBorder;
import idea.sfo.viewer.graphics.ColorSpec;
import idea.sfo.viewer.graphics.ContentLayout;
import idea.sfo.viewer.graphics.Drawable;
import idea.sfo.viewer.graphics.HeaderContent;
import idea.sfo.viewer.graphics.QuestionNumber;
import idea.sfo.viewer.graphics.ResponseContent;
import idea.sfo.viewer.graphics.TextContent;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.TreeMap;


/**
 * Collection of DesignerCol objects.
 * <p/>
 * @author renke002
 */
public class DesignerElement implements Drawable
{

    /**
     * Integer defining the first element of an array.
     */
    public final static int FIRST_ELEMENT = 0;
    /**
     * Background (fill) color for this cell.
     */
    private Color bgColor;
    /**
     * Border for this cell and (if any) those joined to it.
     */
    private CellBorder border;
    /**
     *
     */
    private DesignerElementChildren children;
    /**
     * List of the column numbers that this element spans.
     */
    private int[] colNumbers;
    /**
     * java.awt.Rectangle object that defines this cell's size and placement in
     * the canvas.
     */
    private Rectangle container;
    /**
     * Content to display.
     */
    /*
     * Changed from TextContent to ContentLayout, in order to generealize to
     * different kinds of content, text, graphics, etc...
     */
    private ContentLayout contentLayout;
    /**
     * List of the row numbers that this element spans.
     */
    private int[] rowNumbers;


    /**
     * @param height Height of this element in Fundamental Units.
     * @param width  Width of this element in Fundamental Units.
     */
    /**
     * Constructor for a single unit DesignerElement.
     * <p/>
     * @param cellInfo   designersfo.Cons.CellInfo Object that this element will
     *                   be built on.
     * <p/>
     * @param row        This element's row number
     * <p/>
     * @param col        This element's column number
     * <p/>
     * @param rowHeigths row number to row height mapping for all the rows
     *                   (ConsV elements) defined in the XML.
     * <p/>
     * @param colWidths  column number to column height mapping for all the
     *                   columns (Cons elements) defined in the XML.
     * @param anchor
     * @throws IllegalArgumentException
     * @throws IndexOutOfBoundsException
     * @throws NoSuchElementException
     */
    DesignerElement(
            CellInfo cellInfo ,
            int row ,
            int col ,
            TreeMap<Integer , Long> rowHeigths ,
            TreeMap<Integer , Long> colWidths ,
            Point anchor )
            throws
            IllegalArgumentException ,
            IndexOutOfBoundsException ,
            NoSuchElementException
    {
        // all by myself...
        this.rowNumbers = new int[]
        {
            row
        };
        this.colNumbers = new int[]
        {
            col
        };

        // initialize the contents of this cell
        this.initialize(
                cellInfo ,
                rowHeigths ,
                colWidths ,
                anchor );
    }


    /**
     * Constructor for a multi unit DesignerElement.
     * <p/>
     * @param cellInfo   designersfo.Cons.CellInfo Object that this element will
     *                   be built on.
     * <p/>
     * @param row        This element's row number
     * <p/>
     * @param col        This element's column number
     * <p/>
     * @param rowColMap  Mapping from row numbers to column numbers to CellInfo
     *                   objects, this is necessary to build a set of adjacent
     *                   objects.
     * <p/>
     * @param rowHeigths Mapping between row numbers and heights.
     * <p/>
     * @param colWidths  Mapping between column numbers and widths.
     * <p/>
     * @param anchor
     * @throws IllegalArgumentException
     * @throws IndexOutOfBoundsException
     * @throws NoSuchElementException
     */
    DesignerElement(
            CellInfo cellInfo ,
            int row ,
            int col ,
            TreeMap<Integer , TreeMap<Integer , CellInfo>> rowColMap ,
            TreeMap<Integer , Long> rowHeigths ,
            TreeMap<Integer , Long> colWidths ,
            Point anchor )
            throws
            IllegalArgumentException ,
            IndexOutOfBoundsException ,
            NoSuchElementException
    {
        // we've got company!
        // init this cell and merge the adjacent ones...
        this.mergeCells( cellInfo , row , col );

        // initialize the contents of this cell
        this.initialize(
                cellInfo ,
                rowHeigths ,
                colWidths ,
                anchor );

    }


    /**
     * Constructor for a single cell element.
     * <p/>
     * @param cell
     * @deprecated
     */
    @Deprecated
    public DesignerElement( DesignerCol cell )
    {
    }


    /**
     * Constructor for a multi cell element.
     * <p/>
     * @param cell
     * @param nodes
     * @deprecated
     */
    @Deprecated
    public DesignerElement( DesignerCol cell , HashMap<DesignerRowNode , HashSet<DesignerColNode>> nodes )
    {
        this.merge( nodes );
    }


    /**
     *
     * @return
     */
    private Dimension calcBoxSize( TreeMap<Integer , Long> rowHeigths , TreeMap<Integer , Long> colWidths )
    {
        //long topLeftX, topLeftY;
        long height = 0, width = 0;
        /*
         * Add up the rows for the height.
         */
        for ( int i = 0; i < this.rowNumbers.length; i++ )
        {
            try
            {
                height += rowHeigths.get( this.rowNumbers[i] );
            }
            catch ( NullPointerException npe )
            {
                //
                System.err.println(
                        "Mismatch between the list of row numbers this "
                        + "element spans and the set of available rows." );
            }
        }

        for ( int i = 0; i < this.colNumbers.length; i++ )
        {
            try
            {
                width += colWidths.get( this.colNumbers[i] );
            }
            catch ( NullPointerException npe )
            {
                //
                System.err.println(
                        "Mismatch between the list of column numbers this "
                        + "element spans and the set of available columns." );
            }
        }

        Dimension box = new Dimension(
                Canvas.convertFromFU( width ) ,
                Canvas.convertFromFU( height ) );

        return box;
    }


    /**
     *
     * @param rowHeigths list of the row heights of all the elements on the
     *                   canvas.
     * @param colWidths  list of the column heights of all the elements on the
     *                   canvas.
     * @return point marking the top left corner of this element.
     */
    private Point calcTopCorner( TreeMap<Integer , Long> rowHeigths , TreeMap<Integer , Long> colWidths , Point anchor )
    {
        int firstRow = this.rowNumbers[ FIRST_ELEMENT];
        int firstCol = this.colNumbers[ FIRST_ELEMENT];

        long prevHeights = 0;
        long prevWidths = 0;

        for ( int i = 0; i < firstRow; i++ )
        {
            prevHeights += rowHeigths.get( i );
        }

        for ( int i = 0; i < firstCol; i++ )
        {
            prevWidths += colWidths.get( i );
        }

        Point topLeftCorner = new Point(
                Canvas.convertFromFU( prevWidths ) ,
                Canvas.convertFromFU( prevHeights ) );

        // shift
        topLeftCorner.x += anchor.x;
        topLeftCorner.y += anchor.y;

        return topLeftCorner;
    }


    /**
     * Checks if this element contains the point at the given coordinates.
     * <p/>
     * @param x X coordinate
     * <p/>
     * @param y Y Coordinate
     * <p/>
     * @return true if this element contains the point at the provided
     *         coordinates, false otherwise.
     */
    public boolean contains( int x , int y )
    {
        return this.container.contains( x , y );
    }


    /**
     * Checks if this element is located at row, col; OR if (this is a
     * multi-element cell) and it contains an element at row , col.
     * <p/>
     * @param row Row number
     * <p/>
     * @param col Column number
     * <p/>
     * @return true if this element is located at row , col OR if (this is a
     *         multi-element cell) and it contains an element at row , col.
     */
    public boolean containsCell( int row , int col )
    {
        for ( int r = 0; r < this.rowNumbers.length; r++ )
        {
            if ( this.rowNumbers[r] == row )
            {
                for ( int c = 0; c < this.colNumbers.length; c++ )
                {
                    if ( this.colNumbers[ c] == col )
                    {
                        return true;
                    }
                }
            }
        }
        return false;
    }


    /**
     * Checks if this object wraps a text field.
     * <p/>
     * @return true if this wraps a text field, false otherwise.
     */
    public boolean containsText()
    {
        return ( this.contentLayout instanceof TextContent )
                ? true : false;
    }


    /**
     * Paints this element onto the java.awt.Graphics2D canvas provided.
     * <p/>
     * @param g2d Graphics2D object to use for painting.
     */
    @Override
    public void draw( Graphics2D g2d )
    {
        //
        g2d.setColor( this.bgColor );
        g2d.fill( this.container );

        if ( this.border != null )
        {
            this.border.draw( g2d );
        }

        this.contentLayout.draw( g2d );
    }


    /**
     *
     * @return a list of the col number(s) this element spans.
     */
    public int[] getColNumbers()
    {
        return this.colNumbers;
    }


    /**
     *
     * @return a list of the col number(s) this element spans.
     */
    public String getColString()
    {
        StringBuilder string = new StringBuilder();

        for ( int i = 0; i < this.colNumbers.length; i++ )
        {
            string.append( this.colNumbers[i] );
            if ( i < this.colNumbers.length - 1 )
            {
                string.append( " , " );
            }
        }

        return string.toString();
    }


    /**
     *
     * @return
     */
    public String getHeight()
    {
        return this.container.height + "";
    }


    /**
     *
     * @return
     */
    public String getLabel()
    {
        return this.contentLayout.getLabel();
    }


    /**
     *
     * @return a list of the row number(s) this element spans.
     */
    public int[] getRowNumbers()
    {
        return this.rowNumbers;
    }


    /**
     *
     * @return a list of the row number(s) this element spans.
     */
    public String getRowString()
    {
        StringBuilder string = new StringBuilder();

        for ( int i = 0; i < this.rowNumbers.length; i++ )
        {
            string.append( this.rowNumbers[i] );
            if ( i < this.rowNumbers.length - 1 )
            {
                string.append( " , " );
            }
        }

        return string.toString();
    }


    /**
     *
     * @return
     */
    public String getText()
    {
        if ( this.containsText() )
        {
            // This element wraps a TextContent object, 
            return ( (TextContent) this.contentLayout ).getText();
        }
        return this.contentLayout.getLabel();
    }


    /**
     *
     * @return
     */
    public String getWidth()
    {
        return this.container.width + "";
    }


    /**
     * Initialize this Designer Element with the contents of SFO Cell Info
     * element.
     * <p/>
     * @param cellInfo   SFO CellInfo element used to initialize the local
     *                   variables.
     * <p/>
     * @param rowHeigths Mapping between row numbers and heights.
     * <p/>
     * @param colWidths  Mapping between column numbers and widths.
     * <p/>
     * @throws IllegalArgumentException
     * @throws NoSuchElementException
     */
    private void initialize(
            CellInfo cellInfo ,
            TreeMap<Integer , Long> rowHeigths ,
            TreeMap<Integer , Long> colWidths ,
            Point anchor )
            throws
            IllegalArgumentException ,
            IndexOutOfBoundsException ,
            NoSuchElementException
    {
        /*
         * First of all: calculate the container size and anchor point for this
         * cell. The container is necessary to place and size the borders and
         * the content within this cell.
         */
        this.container = new Rectangle(
                this.calcTopCorner( rowHeigths , colWidths , anchor ) ,
                this.calcBoxSize( rowHeigths , colWidths ) );
        /*
         * The SFO Cell-Format element defines the size, color and placement of
         * the borders and the items inside the cell (text, images, fields, etc)
         */
        CellFormat cellFormat;
        if ( cellInfo.getCellFormat() == null
                || cellInfo.getCellFormat().isEmpty() )
        {
            cellFormat = null;
            this.bgColor = ColorSpec.getDefaultBackgroundColor();
            //
            System.err.println(
                    "SFO Designer format error: no CellFormat object for item "
                    + cellInfo.toString() );
        }
        else
        {
            cellFormat = cellInfo.getCellFormat().get( FIRST_ELEMENT );
            this.bgColor = ColorSpec.parseColorString(
                    cellFormat.getBackgroundColor() );
        }


        /*
         * Once we know the cell's size and coordinates we can use that and the
         * cell-format information to create the borders for this cell.
         */
        this.border = new CellBorder( this.container , cellFormat );


        if ( cellInfo.getCustomContentCellData().isEmpty() == false )
        {
            /*
             * The SFO custom-content-cell-data element provides the data id for
             * the object to display in the cell.
             */
            CustomContentCellData cccData = cellInfo.
                    getCustomContentCellData().
                    get( FIRST_ELEMENT );

//            CustomContentParser ccp = new CustomContentParser( cccData ,
//                    this.border.getInnerContainer() , cellFormat );

            this.contentLayout = DesignerElement.layoutCellDataContent(
                    cccData.getContentId() ,
                    cccData.getRelativeIndex() ,
                    cellFormat ,
                    this.border.getInnerContainer() );
        }
        else
        {
            // https://censuswiki.fenestra.com/bin/view/Main/DesignerMementoSpec
            //
            // we may have
            //      arrow-cell-data> 
            // or
            //      bracket-cell-data
            // or
            //      graphic-cell-data>
            // or
            //      shape-cell-data
        }

    }


    /**
     *
     * @param content_id     Content Identifier number.
     * @param relative_index Relative index of the content withing the database
     *                       table.
     * @return
     */
    public static ContentLayout layoutCellDataContent(
            String content_id ,
            String relative_index ,
            CellFormat cellFormat ,
            Rectangle container )
    {
        /*
         * gids-designer:custom-content-cell-data
         *
         * When opening a question layout in the custom layout designer, the
         * first stage involves gathering up all of the bits and pieces of
         * content from the QUESTION_TITLE, CUSTOM_CONTENT_ITEMS and
         * CUSTOM_RESPONSES tables.
         *
         * Next, the content-id for each cell in the layout is matched to the
         * IDs gathered in the previous step. So, for example, if the content-id
         * matches a CUSTOM_CONTENT_ITEMS.ITEM_ID, and the relative-index is 4,
         * then we know that this cell contains a reference to the ITEM_WORDING
         * for that item, and so on.
         *
         * Labels, headers and reusable blocks work exactly the same way.
         * Pagemaster templates and regions work similarly, but the content is
         * looked up in different places.
         *
         *
         * content-id relative-index interpretation
         *
         * QUESTION_TITLE.QUEST_ID 0 reference to a header or reusable block in
         * its entirety 2 QUESTION_TITLE.TITLE 4 QUESTION_TITLE.QUEST_WORDING 7
         * question number (replaceable token, not explicitly present in
         * content)
         *
         * CUSTOM_CONTENT_ITEMS.ITEM_ID 3 CUSTOM_CONTENT_ITEMS.ITEM_NUMBER 4
         * CUSTOM_CONTENT_ITEMS.ITEM_WORDING 5
         * CUSTOM_CONTENT_ITEMS.HDR_COLUMN_REF 6
         * CUSTOM_CONTENT_ITEMS.HDR_KEYCODE
         *
         * CUSTOM_RESPONSES.RESPONSES_ID 1 reference to the response area itself
         * 4 CUSTOM_RESPONSES.RESPONSE_LABEL +
         * CUSTOM_RESPONSES.RESPONSE_INSTRUCTION (concatenated) 6
         * CUSTOM_RESPONSES.KEYCODE
         *
         * REGION_DEFINITIONS.REGION_DEF_ID 8 reference to computed page/face
         * barcode (ACS/Decennial only) 9 reference to computed page/face page
         * number (ACS/Decennial only)
         *
         */
        String content = null;
        ContentLayout layout = null;
        int relIndex = Integer.parseInt( relative_index );

        switch ( relIndex )
        {
            case 0:
                /*
                 * content-id relative-index interpretation
                 * QUESTION_TITLE.QUEST_ID 0 reference to a header or reusable
                 * block in its entirety
                 *
                 * THIS IS THE HEADER AREA (AKA. RE-USABLE BLOCK) FOR A RESPONSE
                 * FIELD
                 *
                 * 1. get the custom_content_items where quest_id = content_id
                 *
                 * 2. get the (PAPER) SFO doc where quest_id = content_id
                 */
                // 1. check 'custom_header_reb_assn' that this 'content_id' maps to a 'HEADER' 'item_type' 
                // 2. get the 'item_wording' from 'custom_content_items' where 'quest_id' matches this 'content_id' AND 'item_type' = 'HEADER_ITEM'
                // List<List<String>> headers = SfoDbManager.findHeaders( content_id );

                /*
                 * 3. Get the sfo data from 'custom_content_layouts' where
                 * 'quest_id' matches 'content_id' and 'form_media' = 'PAPER'
                 */
                SfoDocumentManager sfoDocMan = new SfoDocumentManager(
                        content_id , SfoEnum.DESIGNER );

                /*
                 */
                Point anchor = new Point( container.x , container.y );

                /*
                 */
                DesignerElementChildren dec = new DesignerElementChildren(
                        sfoDocMan.getDocRoot().getConsVOrConsOrEmptyV() , anchor );

                /*
                 */
                layout = new HeaderContent(
                        dec ,
                        container ,
                        cellFormat );

                // 
                content = null;
                break;
            case 1:
                /*
                 * content-id relative-index interpretation
                 * CUSTOM_RESPONSES.RESPONSES_ID 1 reference to the response
                 * area itself
                 *
                 * THIS IS A RESPONSE AREA.
                 */

                // CustomResponses
                List<CustomResponses> cResponses =
                        SfoDbManager.findCustomResponses( content_id );

                // DcAttributeGroup
                List<DcAttributeGroup> dcAttrGroup = new ArrayList<>();
                // PaperAttributeGroup
                List<PaperAttributeGroup> paperAttrGroup = new ArrayList<>();

                for ( CustomResponses cr : cResponses )
                {
                    dcAttrGroup.addAll(
                            SfoDbManager.findDcAttributeGroup( cr.getAgIdDc() ) );

                    paperAttrGroup.addAll(
                            SfoDbManager.findPaperAttributeGroup(
                            cr.getAgIdPaper().getAgId() ) );
                }

                layout = new ResponseContent(
                        cResponses ,
                        dcAttrGroup ,
                        paperAttrGroup ,
                        container ,
                        cellFormat );
                break;
            case 2:
                /*
                 * content-id relative-index interpretation
                 * QUESTION_TITLE.QUEST_ID 2 QUESTION_TITLE.TITLE
                 */
                content = SfoDbManager.findQuestionTitle( content_id ,
                        relIndex );
                break;
            case 3:
            case 5:
                /*
                 * content-id relative-index interpretation
                 *
                 * CUSTOM_CONTENT_ITEMS.ITEM_ID 3
                 * CUSTOM_CONTENT_ITEMS.ITEM_NUMBER
                 *
                 * CUSTOM_CONTENT_ITEMS.ITEM_ID 5
                 * CUSTOM_CONTENT_ITEMS.HDR_COLUMN_REF
                 */
                content = SfoDbManager.findCustomContentItem( content_id ,
                        relIndex );
                break;
            case 4:
                /*
                 * content-id relative-index interpretation
                 *
                 * QUESTION_TITLE.QUEST_ID 4 QUESTION_TITLE.QUEST_WORDING
                 *
                 * CUSTOM_CONTENT_ITEMS.ITEM_ID 4
                 * CUSTOM_CONTENT_ITEMS.ITEM_WORDING
                 *
                 * CUSTOM_RESPONSES.RESPONSES_ID 4
                 * CUSTOM_RESPONSES.RESPONSE_LABEL +
                 * CUSTOM_RESPONSES.RESPONSE_INSTRUCTION (concatenated)
                 */
                content = SfoDbManager.findQuestionTitle( content_id ,
                        relIndex );
                if ( content == null )
                {
                    content = SfoDbManager.
                            findCustomContentItem( content_id , relIndex );
                }
                if ( content == null )
                {
                    content = SfoDbManager.
                            findCustomResponsesLabel( content_id ,
                            relIndex );
                }
                if ( content == null )
                {
                    // ERROR
                    throw new NoSuchElementException(
                            "The content_id " + content_id + " was not found. " );
                }
                break;
            case 6:
                /*
                 * content-id relative-index interpretation
                 *
                 * CUSTOM_CONTENT_ITEMS.ITEM_ID 6
                 * CUSTOM_CONTENT_ITEMS.HDR_KEYCODE
                 *
                 * CUSTOM_RESPONSES.RESPONSES_ID 6 CUSTOM_RESPONSES.KEYCODE
                 */
                content = SfoDbManager.findCustomContentItem( content_id ,
                        relIndex );
                if ( content == null )
                {
                    content = SfoDbManager.
                            findCustomResponsesLabel( content_id ,
                            relIndex );
                }
                if ( content == null )
                {
                    // ERROR
                    throw new NoSuchElementException(
                            "The content_id " + content_id + " was not found. " );
                }
                break;
            case 7:
                /*
                 * content-id relative-index interpretation
                 *
                 * QUESTION_TITLE.QUEST_ID 7 question number (replaceable token,
                 * not explicitly present in content)
                 */
                layout = new QuestionNumber( container , cellFormat );
                content = null;
                break;
            case 8:
            case 9:
                /**
                 * Decennial.
                 */
                break;
            default:
                /*
                 * Throw some exception, this shouldn't happen.
                 */
                throw new NoSuchElementException(
                        "The content_id " + content_id + " was not found. " );
        }

        //
        if ( content != null && content.isEmpty() == false )
        {
            layout = new TextContent(
                    container ,
                    content ,
                    cellFormat );
        }

        return layout;
    }


    /**
     * Merge this Designer Element cell with the ones joined to it.
     * <p/>
     * @param cellInfo
     * @param row
     * @param col
     */
    private void mergeCells( CellInfo cellInfo , int row , int col )
            throws IllegalStateException , NumberFormatException
    {
        int cellCountH = Integer.parseInt( cellInfo.getJoinedCellCountH() );
        int cellCountV = Integer.parseInt( cellInfo.getJoinedCellCountV() );
        int cellIndexH = Integer.parseInt( cellInfo.getJoinedCellIndexH() );
        int cellIndexV = Integer.parseInt( cellInfo.getJoinedCellIndexV() );

        if ( cellCountH <= 1 && cellCountV <= 1 )
        {
            /*
             * We're initializing a group of joined cells, there must be more
             * than one either horizontally or vertically.
             */
            throw new IllegalStateException(
                    "This function should not have been invoked with a CellInfo"
                    + " element that has no adjecent cells." );
        }
        if ( cellIndexH > 0 && cellIndexV > 0 )
        {
            /*
             * When dealing with a group of cells, the cell-data is ONLY
             * contained in the top-left one: horizontal cell Index = 0 and
             * vertical cell index = 0.
             */
            throw new IllegalStateException(
                    "This function should not have been invoked with a CellInfo"
                    + " element that is not the top-left-most in the set." );
        }

        /*
         * This element spans over multiple rows and columns and we keep track
         * of their numbers by storing them in these two arrays.
         */
        this.rowNumbers = new int[ cellCountV ];
        this.colNumbers = new int[ cellCountH ];

        /*
         * Build the array containing the row numbers that this element spans
         */
        for ( int i = 0; i < cellCountV; i++ )
        {
            this.rowNumbers[ i] = i + row;
        }

        /*
         * Build the array containing the column numbers that this element spans
         */
        for ( int i = 0; i < cellCountH; i++ )
        {
            this.colNumbers[ i] = i + col;
        }
    }


    /**
     * Merges this cell with the adjacent ones.
     * <p/>
     * @param nodes
     * @deprecated
     */
    @Deprecated
    private void merge( HashMap<DesignerRowNode , HashSet<DesignerColNode>> nodes )
    {
        /*
         * Assumption: this function is called after initializing all of this
         * object's local variables.
         */
    }


    /**
     *
     * @param label
     */
    public void setLabel( String label )
    {
        this.contentLayout.setLabel( label );
    }

//    /**
//     *
//     * @param x
//     * @param y
//     */
//    @Override
//    public void moveTo( int x , int y )
//    {
//        this.container.x = x;
//        this.container.y = y;
//    }

    /**
     *
     * @param selected
     */
    public void setSelected( boolean selected )
    {
        this.border.setSelected( selected );
    }


    /**
     *
     */
    private class Position
    {

        private int row, col;


        public Position( int row , int col )
        {
            this.row = row;
            this.col = col;
        }


        public int getCol()
        {
            return this.col;
        }


        public int getRow()
        {
            return this.row;
        }

    }

    /**
     * Utility class that parses a CustomContentCellData object in order to
     * determine the kind of content it refers to.
     * <p/>
     * gids-designer:custom-content-cell-data
     * <p/>
     * When opening a question layout in the custom layout designer, the first
     * stage involves gathering up all of the bits and pieces of content from
     * the QUESTION_TITLE, CUSTOM_CONTENT_ITEMS and CUSTOM_RESPONSES tables.
     * <p/>
     * Next, the content-id for each cell in the layout is matched to the IDs
     * gathered in the previous step. So, for example, if the content-id matches
     * a CUSTOM_CONTENT_ITEMS.ITEM_ID, and the relative-index is 4, then we know
     * that this cell contains a reference to the ITEM_WORDING for that item,
     * and so on.
     * <p/>
     * Labels, headers and reusable blocks work exactly the same way. Pagemaster
     * templates and regions work similarly, but the content is looked up in
     * different places.
     * <p/>
     *
     * content-id relative-index interpretation
     * <p/>
     * QUESTION_TITLE.QUEST_ID 0 reference to a header or reusable block in its
     * entirety 2 QUESTION_TITLE.TITLE 4 QUESTION_TITLE.QUEST_WORDING 7 question
     * number (replaceable token, not explicitly present in content)
     * <p/>
     * CUSTOM_CONTENT_ITEMS.ITEM_ID 3 CUSTOM_CONTENT_ITEMS.ITEM_NUMBER 4
     * CUSTOM_CONTENT_ITEMS.ITEM_WORDING 5 CUSTOM_CONTENT_ITEMS.HDR_COLUMN_REF 6
     * CUSTOM_CONTENT_ITEMS.HDR_KEYCODE
     * <p/>
     * CUSTOM_RESPONSES.RESPONSES_ID 1 reference to the response area itself 4
     * CUSTOM_RESPONSES.RESPONSE_LABEL + CUSTOM_RESPONSES.RESPONSE_INSTRUCTION
     * (concatenated) 6 CUSTOM_RESPONSES.KEYCODE
     * <p/>
     * REGION_DEFINITIONS.REGION_DEF_ID 8 reference to computed page/face
     * barcode (ACS/Decennial only) 9 reference to computed page/face page
     * number (ACS/Decennial only)
     * <p/>
     */
//    private class CustomContentParser
//    {
//
//        private String contentId;
//        private String customContent;
//        private String relativeIndex;
//
//
//        private CustomContentParser( CustomContentCellData cccData , Rectangle innerSize , CellFormat format )
//        {
//            this.contentId = cccData.getContentId();
//            this.relativeIndex = cccData.getRelativeIndex();
//        }
//
//
//        /**
//         *
//         * @param content_id
//         * @param relative_index
//         * @return
//         */
//        public ContentLayout findCellDataContent( String content_id , String relative_index )
//        {
//            /*
//             * gids-designer:custom-content-cell-data
//             *
//             * When opening a question layout in the custom layout designer, the
//             * first stage involves gathering up all of the bits and pieces of
//             * content from the QUESTION_TITLE, CUSTOM_CONTENT_ITEMS and
//             * CUSTOM_RESPONSES tables.
//             *
//             * Next, the content-id for each cell in the layout is matched to
//             * the IDs gathered in the previous step. So, for example, if the
//             * content-id matches a CUSTOM_CONTENT_ITEMS.ITEM_ID, and the
//             * relative-index is 4, then we know that this cell contains a
//             * reference to the ITEM_WORDING for that item, and so on.
//             *
//             * Labels, headers and reusable blocks work exactly the same way.
//             * Pagemaster templates and regions work similarly, but the content
//             * is looked up in different places.
//             *
//             *
//             * content-id relative-index interpretation
//             *
//             * QUESTION_TITLE.QUEST_ID 0 reference to a header or reusable block
//             * in its entirety 2 QUESTION_TITLE.TITLE 4
//             * QUESTION_TITLE.QUEST_WORDING 7 question number (replaceable
//             * token, not explicitly present in content)
//             *
//             * CUSTOM_CONTENT_ITEMS.ITEM_ID 3 CUSTOM_CONTENT_ITEMS.ITEM_NUMBER 4
//             * CUSTOM_CONTENT_ITEMS.ITEM_WORDING 5
//             * CUSTOM_CONTENT_ITEMS.HDR_COLUMN_REF 6
//             * CUSTOM_CONTENT_ITEMS.HDR_KEYCODE
//             *
//             * CUSTOM_RESPONSES.RESPONSES_ID 1 reference to the response area
//             * itself 4 CUSTOM_RESPONSES.RESPONSE_LABEL +
//             * CUSTOM_RESPONSES.RESPONSE_INSTRUCTION (concatenated) 6
//             * CUSTOM_RESPONSES.KEYCODE
//             *
//             * REGION_DEFINITIONS.REGION_DEF_ID 8 reference to computed
//             * page/face barcode (ACS/Decennial only) 9 reference to computed
//             * page/face page number (ACS/Decennial only)
//             *
//             */
//            String content = null;
//            ContentLayout layout = null;
//            int relIndex = Integer.parseInt( relative_index );
//            switch ( relIndex )
//            {
//                case 0:
//                    /*
//                     * content-id relative-index interpretation
//                     * QUESTION_TITLE.QUEST_ID 0 reference to a header or
//                     * reusable block in its entirety
//                     *
//                     * 1. get the custom_content_items where quest_id =
//                     * content_id
//                     *
//                     * 2. get the (PAPER) SFO doc where quest_id = content_id
//                     */
//                    // 1. check 'custom_header_reb_assn' that this 'content_id' maps to a 'HEADER' 'item_type' 
//                    // 2. get the 'item_wording' from 'custom_content_items' where 'quest_id' matches this 'content_id' AND 'item_type' = 'HEADER_ITEM'
//                    List<List<String>> headers = SfoDbManager.findHeaders(
//                            content_id );
//
//                    /*
//                     * 3. Get the sfo data from 'custom_content_layouts' where
//                     * 'quest_id' matches 'content_id' and 'form_media' =
//                     * 'PAPER'
//                     */
//                    SfoDocumentManager sfoDocMan = new SfoDocumentManager(
//                            content_id , SfoEnum.DESIGNER );
//
//                    DesignerElementChildren dec = new DesignerElementChildren(
//                            sfoDocMan.getDocRoot().getConsVOrConsOrEmptyV() );
//
//                    dec.getGraphics();
//                    break;
//                case 1:
//                    /*
//                     * content-id relative-index interpretation
//                     * CUSTOM_RESPONSES.RESPONSES_ID 1 reference to the response
//                     * area itself
//                     */
//                    SfoDbManager.findCustomResponses( content_id , relIndex );
//                    break;
//                case 2:
//                    /*
//                     * content-id relative-index interpretation
//                     * QUESTION_TITLE.QUEST_ID 2 QUESTION_TITLE.TITLE
//                     */
//                    /*
//                     * The cell-info object containes a cell-data element, so we
//                     * need to find where the linked content is.
//                     */
//                    content = SfoDbManager.findQuestionTitle( content_id ,
//                            relIndex );
//
//                    if ( content != null && content.isEmpty() == false )
//                    {
////                        layout = new TextContent(
////                                this.border.getInnerContainer() ,
////                                content ,
////                                cellFormat );
//                    }
//
//
//
//                    break;
//                case 3:
//                case 5:
//                    /*
//                     * content-id relative-index interpretation
//                     *
//                     * CUSTOM_CONTENT_ITEMS.ITEM_ID 3
//                     * CUSTOM_CONTENT_ITEMS.ITEM_NUMBER
//                     *
//                     * CUSTOM_CONTENT_ITEMS.ITEM_ID 5
//                     * CUSTOM_CONTENT_ITEMS.HDR_COLUMN_REF
//                     */
//                    content = SfoDbManager.findCustomContentItem( content_id ,
//                            relIndex );
//                    break;
//                case 4:
//                    /*
//                     * content-id relative-index interpretation
//                     *
//                     * QUESTION_TITLE.QUEST_ID 4 QUESTION_TITLE.QUEST_WORDING
//                     *
//                     * CUSTOM_CONTENT_ITEMS.ITEM_ID 4
//                     * CUSTOM_CONTENT_ITEMS.ITEM_WORDING
//                     *
//                     * CUSTOM_RESPONSES.RESPONSES_ID 4
//                     * CUSTOM_RESPONSES.RESPONSE_LABEL +
//                     * CUSTOM_RESPONSES.RESPONSE_INSTRUCTION (concatenated)
//                     */
//                    content = SfoDbManager.findQuestionTitle( content_id ,
//                            relIndex );
//                    if ( content == null )
//                    {
//                        content = SfoDbManager.
//                                findCustomContentItem( content_id , relIndex );
//                    }
//                    if ( content == null )
//                    {
//                        content = SfoDbManager.findCustomResponsesLabel( content_id ,
//                                relIndex );
//                    }
//                    if ( content == null )
//                    {
//                        // ERROR
//                        throw new NoSuchElementException(
//                                "The content_id " + content_id + " was not found. " );
//                    }
//                    break;
//                case 6:
//                    /*
//                     * content-id relative-index interpretation
//                     *
//                     * CUSTOM_CONTENT_ITEMS.ITEM_ID 6
//                     * CUSTOM_CONTENT_ITEMS.HDR_KEYCODE
//                     *
//                     * CUSTOM_RESPONSES.RESPONSES_ID 6 CUSTOM_RESPONSES.KEYCODE
//                     */
//                    content = SfoDbManager.findCustomContentItem( content_id ,
//                            relIndex );
//                    if ( content == null )
//                    {
//                        content = SfoDbManager.findCustomResponsesLabel( content_id ,
//                                relIndex );
//                    }
//                    if ( content == null )
//                    {
//                        // ERROR
//                        throw new NoSuchElementException(
//                                "The content_id " + content_id + " was not found. " );
//                    }
//                    break;
//                case 7:
//                    /*
//                     * content-id relative-index interpretation
//                     *
//                     * QUESTION_TITLE.QUEST_ID 7 question number (replaceable
//                     * token, not explicitly present in content)
//                     */
//                    content = ".#.";
//                    break;
//                case 8:
//                case 9:
//                    /**
//                     * Decennial.
//                     */
//                    break;
//                default:
//                    /*
//                     * Throw some exception, this shouldn't happen.
//                     */
//                    throw new NoSuchElementException(
//                            "The content_id " + content_id + " was not found. " );
//            }
//            // get DB connection        
//            // find stuff.
//            //content = SfoDbManager.layoutCellDataContent( content_id , relative_index );
//
//            return layout;
//        }
//
//
//        /**
//         *
//         * @return
//         */
//        public ContentLayout layoutContent()
//        {
//            return findCellDataContent( this.contentId , this.relativeIndex );
//        }
//
//    }
}
